// 请求
import "reflect-metadata";

// 元数据
function methodDecorator(method: string) {
  // 柯里化
  return function (path: string) {
    // 对被装饰的方法，增加描述信息
    // 例如 addArticle
    // addArticle 增加method 、path的描述信息
    return function (target: any, key: string, descriptor: PropertyDescriptor) {
      Reflect.defineMetadata("method", method, descriptor.value);
      Reflect.defineMetadata("path", path, descriptor.value);
    };
  };
}
function Controller(path?: string) {
  return function (Target: any) {
    // 给类增加了一个元数据 path = '/article'
    Reflect.defineMetadata("path", path ?? "", Target);
  };
}
const Get = methodDecorator("get");
const Post = methodDecorator("post");
const Delete = methodDecorator("delete");
@Controller("/article")
class ArtileController {
  @Get("/detail")
  getDetial() {
    return {
      err: 0,
      data: "get Detail",
    };
  }
  @Post("/add")
  addArticle() {
    return {
      err: 0,
      data: "post add",
    };
  }
  @Delete("/remove")
  removeArticle() {
    return "remove article";
  }
}
// nestjs的写法
// get /article/detail -> { err: 0,data: "get Detail" };
// post /article/add -> { err: 0, data: "post add"  };

function createRoutes(instance: any) {
  // 获取实例的原型
  const prototype = Reflect.getPrototypeOf(instance)!;
  const controllerPath = Reflect.getMetadata("path", prototype.constructor);
  // 去掉constructor
  const protoKeys = Reflect.ownKeys(prototype).filter(
    (item) => item !== "constructor"
  );
  return protoKeys.map((key) => {
    const requestHandler = (prototype as any)[key];
    const requestMethod = Reflect.getMetadata("method", requestHandler);
    const requestPath = Reflect.getMetadata("path", requestHandler);

    return {
      requestPath: `${controllerPath}${requestPath}`,
      requestMethod,
      requestHandler,
    };
  });
}
// 创建路由表
const routes = createRoutes(new ArtileController());
console.log(routes);

// 通过装饰器实现路由系统
export {};

{
  //nestjs mvc
  // /article/add/article/detail /article/remove
  @Controller("/article")
  class Articlecontroller {
    @Post("/add")
    addArticle() {
      return "add article";
    }
    @Get("/detail")
    getDetail() {
      return "detail";
    }
    @Delete("/remove")
    removeArticle() {
      return "remove article";
    }
  }
  // post /article/add> "add article"
  //get /article/detail ->'detail'
}
